home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Best of MacTutor - S…e Code for Volumes 1 to 5
/
The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin
/
Source Code
/
#29 (Feb 88)
/
scsi forth driver
/
Scsidisk2.fth
Wrap
Text File
|
1987-12-18
|
24KB
|
904 lines
only forth definitions
also mac also assembler
CODE SCALE
MOVE.L (A6)+,D0
BMI.S @1
MOVE.L (A6),D1
ASL.L D0,D1
MOVE.L D1,(A6)
RTS
@1 MOVE.L (A6),D1
NEG.L D0
ASR.L D0,D1
MOVE.L D1,(A6)
RTS
END-CODE
: 4ASCII 0
4 0 DO 8 SCALE 0 WORD 1+ C@ + LOOP
;
( *** compiler support words for external definitions *** )
: :xdef
create -4 allot
$4EFA w, ( JMP )
0 w, ( entry point to be filled later )
0 , ( length of routine to be filled later )
here 6 - 76543
;
: ;xdef { branch marker entry | -- }
marker 76543 <> abort" xdef mismatch"
entry branch - branch w!
here branch - 2+ branch 2+ !
;
: xlen 4 + @ ; ( get length word of external definition )
( *** driver header block *** )
0 CONSTANT drvrFlags
2 CONSTANT drvrdelay
4 CONSTANT drvrEMask
6 CONSTANT drvrMenu
8 CONSTANT drvrOpen
10 CONSTANT drvrPrime
12 CONSTANT drvrCtl
14 CONSTANT drvrStatus
16 CONSTANT drvrClose
18 CONSTANT drvrname
50 CONSTANT DAlength
( *** compiler support words for DA and driver definitions *** )
: :DA
create -4 allot
here 87654 ( start of DA block, and marker )
54 allot ( length of block )
;
: ;DA { DAstart marker Ropen Rprime Rctl Rstatus Rclose
Rflags Rdelay Remask Rmenu Rname | -- }
marker 87654 <> abort" DA definition mismatch"
Ropen DAStart - DAStart drvrOpen + w!
Rprime DAStart - DAStart drvrPrime + w!
Rctl DAStart - DAStart drvrCtl + w!
Rstatus DAStart - DAStart drvrStatus + w!
Rclose DAStart - DAStart drvrClose + w!
Rflags DAStart drvrFlags + w!
Rdelay DAStart drvrDelay + w!
Remask DAStart drvrEmask + w!
RMenu DAStart drvrMenu + w!
Rname count dup DAStart drvrName + c!
DAStart drvrName + 1+ swap
dup 31 > if drop 31 then cmove
here DAstart - DAStart DAlength + !
;
: DAlen DAlength + @ ; ( get length word of external definition )
\ —————————————————————————————————————
\ some macros needed in the driver
\ —————————————————————————————————————
CODE xchg ( exchange word halves on top of stack )
move.l (a6)+,d1
swap.w d1
move.l d1,-(a6)
rts
END-CODE MACH
CODE min
MOVE.L (A6)+,D0
CMP.L (A6),D0
BGE.S @1
MOVE.L D0,(A6)
@1 RTS
END-CODE MACH
CODE shl ( data #bits )
MOVE.L (A6)+,D0
MOVE.L (A6),D1
LSL.L D0,D1
MOVE.L D1,(A6)
RTS
END-CODE MACH
CODE shr ( data #bits )
MOVE.L (A6)+,D0
MOVE.L (A6),D1
LSR.L D0,D1
MOVE.L D1,(A6)
RTS
END-CODE MACH
CODE w*
MOVE.L (A6)+,D1
MOVE.L (A6)+,D0
MULS.W D1,D0
MOVE.L D0,-(A6)
RTS
END-CODE MACH
\ —————————————————————————————————————
\ **** DA glue macros
\ —————————————————————————————————————
$8FC CONSTANT JioDone
CODE DA.prelude
LINK A6,#-512 ( 512 bytes of local Forth stack )
MOVEM.L A0-A1,-(A7) ( save registers )
MOVE.L A6,A3 ( setup local loop return stack )
SUBA.L #256,A3 ( in the low 256 local stack bytes )
MOVE.L A0,-(A6) ( parameter block )
MOVE.L A1,-(A6) ( device control entry )
RTS \ just to indicate the MACHro stops here
END-CODE MACH
CODE DA.epilogue
MOVE.L (A6)+,D0 ( return code )
MOVEM.L (A7)+,A0-A1 ( restore registers )
UNLK A6
RTS
END-CODE MACH
CODE DA.JIODone
MOVE.L (A6)+,D0 ( return code )
MOVEM.L (A7)+,A0-A1 ( restore registers )
UNLK A6
move.l JIODone,A0
movem.l d4-d7/a4-a6,-(a7)
jsr (a0)
movem.l (a7)+,d4-d7/a4-a6
RTS
END-CODE MACH
.trap _newptr,sys,clr $A71E
\ fields of device control entry
4 CONSTANT dCtlFlags
6 CONSTANT dCtlQHdr
16 CONSTANT dCtlPosition
20 CONSTANT dCtlStorage
24 CONSTANT dCtlRefNum
26 CONSTANT dCtlCurTicks
30 CONSTANT dCtlWindow
34 CONSTANT dCtlDelay
36 CONSTANT dCtlEMask
38 CONSTANT dCtlMenu
\ parameter block constants
0 CONSTANT qLink \ pointer to next queue entry [long word]
4 CONSTANT qType \ queue type [word]
6 CONSTANT ioTrap \ routine trap [word]
7 CONSTANT ioTrap+1 \ read or write command
8 CONSTANT ioCmdAddr \ routine address [long word]
12 CONSTANT ioCompletion \ addr of completion routine [long word]
16 CONSTANT ioResult \ result code returned here [word]
18 CONSTANT ioNamePtr \ holds pointer to file name string or
22 CONSTANT ioVRefNum \ volume reference number
26 CONSTANT csCode ( type of control call )
28 CONSTANT csParam ( control call parameters )
\ MFS I/O Parameter Block
24 CONSTANT ioRefNum
26 CONSTANT ioVersNum
27 CONSTANT ioPermssn
28 CONSTANT ioMisc
32 CONSTANT ioBuffer
36 CONSTANT ioReqCount
40 CONSTANT ioActCount
44 CONSTANT ioPosMode
46 CONSTANT ioPosOffset
50 CONSTANT IOParamBlkSize
4ascii SDRV constant "sdrv
4ascii TFS1 constant "tfs1
\ Equates
\ My excuses for the format. This has been taken almost
\ 'as is' from Apple's SCSI driver example. - jl -
EQU verChar $34 \ version '4'
EQU SCSIZE 10 \ size of SCSI extended command
\ Equates for our storage (pointed to by DCtlStorage)
EQU Offset 0 \ [long] offset of starting sector
EQU MyDQEl Offset+4 \ [20 bytes] drive queue element (with flags) for this drive
EQU MyDrvNum MyDQEl+20 \ [word] drive num (determined by scanning drive queue)
EQU NextAddr MyDrvNum+2 \ [long] ptr to current block buffer
EQU TickleFlag NextAddr+4 \ [byte] Do we need to remind the system about this drive?
EQU BlindOK TickleFlag+1 \ [byte] Can we use blind reads?
\ I left this in to keep the format the same.
\ We don't need it since our driver does not read blind.
EQU SCmd BlindOK+1 \ [10 bytes] SCSI extended cmd Block /JL
EQU StatWord SCmd+10 \ [word] status and message bytes...
EQU MsgWord StatWord+2 \ [word] ... returned by SCSIComplete
EQU OurID MsgWord+2 \ [word] our SCSI ID
EQU SCSIPseudo OurID+2 \ [30 bytes] SCSI pseudo-code program - three instructions long
EQU SCSIPar1 SCSIPseudo+2 \ first SCSI code parameter (long)
EQU SCSIPar2 SCSIPar1+4 \ 2nd SCSI code parameter (long)
EQU DiskVarLth SCSIPseudo+(SCSIZE*3) \ length of our locals . . .
EQU DQDrvSize 12
EQU realSize MyDQEl+DQDrvSize+4
\ equates for CSParam offsets for our special control call
EQU DSCCmd CSParam \ Ptr to SCSI command block
EQU DSCPseudo DSCCmd+4 \ Ptr to SCSI pseudocode (if any bytes to xfer)
EQU DSCBuffer DSCPseudo+4 \ Ptr to buffer for transfer (if any)
EQU DSCSize DSCBuffer+4 \ Size of transfer, signed (+ if read, - if write)
EQU DSCTicks DSCSize+4 \ Tick count we're willing to wait for completion
EQU DSCCmdSize DSCTicks+4 \ (word) Size of command block we're sending (usually 6)
EQU KillCode 1
EQU VerifyCode 5
EQU FormatCode 6
EQU EjectCode 7
EQU IconCode 21
EQU AccRun 65
EQU SCSICode 77 \ our own special code (defined above)
EQU ControlErr -1
EQU StatusErr -1
EQU ParamErr -50
EQU nsDrvErr -56
EQU nsVErr -35
EQU ioErr -36
EQU dNeedTime $DFFF \ to clear bit 5 of high byte in drvrFlags
EQU DiskInsertEvt 7
EQU SysEvtMask $144
EQU UTableBase $11C
EQU DrvQHdr $308
EQU QHead $2
EQU DQDrive 6
EQU DQRefNum 8
EQU DQFSid 10
EQU PDSig 0
EQU PDSigWord $5453
EQU PDFSID 8
EQU PDLen 12
\ _______________________________________________________________________
\ The code starts here.
\ _______________________________________________________________________
:XDEF ScsiDisk \ compiles a jump to the install code at the end
\ which will be resolved at the end of the definition.
:DA DiskDrvr \ this word provides the driver header structure
.ALIGN
\ Q200 Icon, as given by Quantum
\ If you find this 'snail' ugly, feel free to change it ...
\ J.L.
header SCSIIcon
DC.L $00000000 DC.L $00000000 DC.L $00000000 DC.L $000FF000
DC.L $003FFC00 DC.L $00FFFF00 DC.L $01FFFF80 DC.L $03F81FC0
DC.L $07E007E0 DC.L $07C003E0 DC.L $0F8001F0 DC.L $0F0000F0
DC.L $1F0000F8 DC.L $1E000078 DC.L $1E000078 DC.L $1E000078
DC.L $1E000078 DC.L $1E000078 DC.L $1E000078 DC.L $1F0000F8
DC.L $0F0000F0 DC.L $0F8001F0 DC.L $07C003E0 DC.L $07E007E0
DC.L $03F80000 DC.L $01FFFFF0 DC.L $00FFFFF8 DC.L $003FFFF8
DC.L $000FFFF8 DC.L $00000000 DC.L $00000000 DC.L $00000000
DC.L $00000000 DC.L $00000000 DC.L $000FF000 DC.L $003FFC00
DC.L $00FFFF00 DC.L $01FFFF80 DC.L $03FFFFC0 DC.L $07FFFFE0
DC.L $0FFFFFF0 DC.L $0FFFFFF0 DC.L $1FFFFFF8 DC.L $1FFFFFF8
DC.L $3FFFFFFC DC.L $3FFFFFFC DC.L $3FFFFFFC DC.L $3FFFFFFC
DC.L $3FFFFFFC DC.L $3FFFFFFC DC.L $3FFFFFFC DC.L $3FFFFFFC
DC.L $1FFFFFF8 DC.L $1FFFFFF8 DC.L $0FFFFFF0 DC.L $0FFFFFF0
DC.L $07FFFFF0 DC.L $03FFFFF8 DC.L $01FFFFFC DC.L $00FFFFFC
DC.L $003FFFFC DC.L $000FFFFC DC.L $00000000 DC.L $00000000
\ Our "Where:" string
DC.B 11
DC.B 'Q200 (SCSI)'
.ALIGN
\ SCSI handler glue routines
CODE SCSIReset ( -- result code )
CLR.W -(A7)
MOVE.W #0,-(A7)
_SCSIDispatch
MOVE.W (A7)+,D0
EXT.L D0
MOVE.L D0,-(A6)
RTS
END-CODE
CODE SCSIGet ( -- result code )
CLR.W -(A7)
MOVE.W #1,-(A7)
_SCSIDispatch
MOVE.W (A7)+,D0
EXT.L D0
MOVE.L D0,-(A6)
RTS
END-CODE
CODE SCSISelect ( TargetID -- SCSIErrorResult )
MOVE.L (A6)+,D0
CLR.W -(A7)
MOVE.W D0,-(A7)
MOVE.W #2,-(A7)
_SCSIDispatch
MOVE.W (A7)+,D0
EXT.L D0
MOVE.L D0,-(A6)
RTS
END-CODE
CODE SCSICmd ( buffer count -- SCSIErrorResult )
MOVE.L (A6)+,D0
MOVE.L (A6)+,D1
CLR.W -(A7)
MOVE.L D1,-(A7)
MOVE.W D0,-(A7)
MOVE.W #3,-(A7)
_SCSIDispatch
MOVE.W (A7)+,D0
EXT.L D0
MOVE.L D0,-(A6)
RTS
END-CODE
CODE SCSIComplete ( waitTicks mess stat -- SCSIErrorResult )
CLR.W -(A7)
MOVE.L (A6)+,-(A7)
MOVE.L (A6)+,-(A7)
MOVE.L (A6)+,-(A7)
MOVE.W #4,-(A7)
_SCSIDispatch
MOVE.W (A7)+,D0
EXT.L D0
MOVE.L D0,-(A6)
RTS
END-CODE
1 CONSTANT SCInc 2 CONSTANT SCnoInc
3 CONSTANT SCAdd 4 CONSTANT SCMove
5 CONSTANT SCLoop 6 CONSTANT SCNop
7 CONSTANT SCStop 8 CONSTANT SCComp
\ ———————————————————————————————
\ main driver routines start here
\ ———————————————————————————————
: SCSICommon
\ written to emulate the SCSICommon
\ routine in Apple's example
\ as closely as possible.
{ pseudo cmdblock ourVars ticks bytes cmdsize
| writing mess stat -- result }
SCSIGet 0= IF
ourVars ourID + w@
SCSISelect 0= IF
cmdBlock cmdSize SCSICmd 0= bytes AND IF
pseudo bytes 0< \ bytes <0 if writing
IF (call) SCSIWrite drop
ELSE (call) SCSIRead drop THEN
\ Note: Your system may be able to support blind transfers.
\ Here is the place to experiment with such things ---
THEN
ticks ^ mess ^ stat SCSIComplete
0= IF
stat $FF AND IF ioErr ( there was an SCSI error )
ELSE 0 ( successful completion ) THEN
ELSE ( complete unsuccessful ) ioErr
THEN
ELSE ( select unsuccessful ) ioErr
THEN
ELSE ( get unsuccessful ) ioErr
THEN
;
: DiskClose { parblk dce | -- result }
0 ( result code = OK ) ;
: diskControl { parblk dce | ourVars -- result }
dce DCtlStorage + @ -> ourVars
parblk csCode + w@
CASE
killCode OF 0 ENDOF
verifyCode OF 0 ENDOF
formatCode OF 0 ENDOF
ejectCode OF
ourVars MyDrvNum + w@ \ check drive # in request
parblk IOVRefNum + w@ = \ the same?
IF
SysEvtMask w@ IF ( we're not at boot time )
DiskInsertEvt
MyDrvNum ourVars + w@
(call) PostEvent drop
ELSE ( boot time )
1 ourVars tickleFlag + c!
( drive will be remembered after boot )
THEN
controlErr
ELSE nsDrvErr
THEN
ENDOF
iconCode OF ['] SCSIIcon parblk csParam + !
0 ENDOF
accRun OF
ourVars tickleFlag + c@
ourVars offset + @ 0= not
( we have a good partition )
AND
IF
DiskInsertEvt
MyDrvNum ourVars + w@
(call) PostEvent drop
THEN
0 dce DCtlDelay + w!
dce DCtlFlags + dup w@
dNeedTime AND swap w! ( clear flag )
0 ourVars tickleFlag + c!
0 ENDOF
scsiCode OF
parblk dup DSCPseudo + @
dup DSCCmd + @
ourVars
dup DSCTicks + @
dup DSCSize + @
DSCCmdSize + w@
SCSICommon
ENDOF
( otherwise )
controlErr
ENDCASE
;
: DiskStatus { parblk dce | -- result } statusErr ;
CODE GetSysPtr
move.l (a6)+,d0
_newptr,sys,clr
move.l a0,-(a6)
rts
END-CODE
CODE AddDrv ( dqe refnum drv# | -- )
move.l (a6)+,d0
move.l (a6)+,d1
swap.w d0
move.w d1,d0
move.l (a6)+,a0
_AddDrive
rts
END-CODE
: DiskOpen { parblk dce |
ourVars thisQElem driveNum dqe SCSIprog -- result }
DiskVarLth GetSysPtr dup \ get memory for local variables
-> ourVars dce DCtlStorage + ! \ and store pointer to it
100 5 DO \ find unused drive #
DrvQHdr QHead + @ -> thisQElem \ scan queue
BEGIN thisQElem 0= IF i leave THEN
\ end of queue? we have a good number
thisQElem DQDrive + w@
i <> WHILE \ keep scanning as long as # is not in use
thisQElem ( QLink + ) @ -> thisQElem
REPEAT
LOOP -> driveNum
driveNum ourVars myDrvNum + w! \ remember drive # in local vars
\ Add a drive to the drive queue. First, some fun facts:
\
\ The drive queue element starts four bytes before the DQEPtr! These
\ four bytes contain "hardware-locked", "ejectable", and "disk-in-place" info.
\
\ Not As Interesting But Still True: HFS supports volumes >32MBytes,
\ but since the dqDrvSize field in the DQE is only a word, the Software Gurus
\ had to resort to bizarre sorcery: If the qType field (formerly unused in
\ DQE's) is 1, the word following the dqDriveSize field is assumed to be
\ the high-order word of a LongInt block count! (dqDriveSize is still the low-
\ order word). It works even if the size doesn't require both words,
\ so we always do it this way.
\
\ See: Tech Note #36.
ourVars MyDQEl + 8 over w! \ set non-ejectable and clear the rest
2+ 0 over w! 2+ -> dqe \ this is the real start of the DQElem
1 dqe qType + w! \ large vol queue type
0 dqe dqDrvSize + ! \ no size yet
0 dqe dQFSID + w! \ normal file system
dqe
dce DCtlRefNum + w@
driveNum AddDrv \ add drive to queue
\ now set up the SCSI pseudo program in driver's local vars
ourVars SCSIPseudo + -> SCSIprog
scnoinc SCSIprog w!
scstop SCSIprog scsize + w!
0 \ result code = good
;
: DiskPrime { parblk dce |
ourVars sectors bytes start size r/w sect transferred error -- result }
dce dCtlStorage + @ -> ourVars \ setup local var pointer
1 ourVars TickleFlag + c!
\ convert byte count into number of sectors
parblk IOReqCount + @ 9 shr $1FFFFF AND -> sectors
\ convert starting position into sector number
dce dCtlPosition + @ 9 shr $1FFFFF AND -> start
ourVars realSize + @ xchg -> size \ get drive size
start sectors + size 1+ < IF ( valid request )
0 -> transferred
ourVars ( offset + ) @ +> start \ offset by start of partition
parBlk IOTrap+1 + c@ 3 = ( is this a write command? )
IF -1 -> r/w $2A00 ( SCSI extended write )
ELSE 1 -> r/w $2800 ( SCSI extended read )
THEN
ourVars SCmd + w! \ put the command away
BEGIN ( transfer loop )
\ If you have problems getting the SCSI transfer to work
\ with your particular disk, try changing the number of
\ sectors transferred on each call ( 127 here )
\ or change the read/write extended to a normal read/write.
\ Note that in that case you'll have to change the command
\ block setup as well.
127 sectors min -> sect
transferred +> start
parblk IOBuffer + @ transferred 9 shl +
ourVars SCSIPar1 + !
sect 9 shl dup -> bytes
ourVars SCSIPar2 + ! \ set # of bytes
start ourVars SCmd + 2+ !
\ set starting position in command block
bytes 2/ ourVars SCmd + 6 + ! \ set # of sectors
IOErr ( preset, in case loop with retry is unsuccessful )
10 0 DO ( retry max 10 times )
ourVars SCSIPseudo +
ourVars SCmd +
ourVars 60 r/w 10
SCSICommon 0= IF drop 0 leave THEN
1 (call) sysbeep \ just for debugging,
\ beeps if SCSI did not complete successfully
LOOP -> error
-127 +> sectors
sectors 1- 0<
UNTIL ( transfer loop )
error dup 0= IF
parBlk IOReqCount + @ -> bytes
bytes parBlk IOActCount + !
\ we transferred the # of bytes requested
bytes dce DCtlPosition + +!
THEN
ELSE IOErr
THEN
;
CODE DrvrInst ( unitNum | -- )
move.l (a6)+,d0
not.w d0
_DrvrInstall
rts
END-CODE
CODE DrvrRem ( unitNum | -- )
move.l (a6)+,d0
not.w d0
_DrvrRemove
rts
END-CODE
CODE openMe ( drvrName | result -- )
\ allocates a parameter block on the A7 stack and calls
\ the _open trap. This is easier to do in assembly ---
moveq.l #(IOParamBlkSize/2)-1,d0
@1 clr.w -(a7)
dbra d0,@1
move.l a7,a0
move.l (a6)+,IONamePtr(a0)
_Open
add.w #IOParamBlkSize,a7
move.l d0,-(a6)
rts
END-CODE
: RealInstall
\ This routine is called by the system boot code with
\ the SCSI ID of the disk in D5 and a pointer to its
\ partition map in A0. We therefore need some special glue code.
\ Note that Mach2 allows to do the stack parameter / local
\ variable declaration after this glue code without any problems
LINK A6,#-512 ( 512 bytes of local Forth stack )
MOVEM.L A2-A6/D2-D7,-(A7) ( save registers )
MOVE.L A6,A3 ( setup local loop return stack )
SUBA.L #256,A3 ( in the low 256 local stack bytes )
MOVE.L A0,-(A6) ( partition table pointer )
MOVE.L D5,-(A6) ( SCSI ID )
{ partition ID | unitNum hdce dce ourVars pt -- }
ID 32 + -> unitNum
unitNum DrvrInst \ allocate DCE and install it
unitNum 4 w* UTableBase @ + @ -> hdce \ dce handle
hdce @ -> dce \ get dce pointer
['] DiskDrvr dce ( DCtlDriver + ) ! \ put pointer to driver into dce
['] DiskDrvr drvrFlags + w@
dce DCtlFlags + w! \ move driver flags, RAMbase should be cleared
0 dce DCtlDelay + w! \ no time needed yet
['] DiskDrvr drvrEMask + @
dce DCtlEMask + ! \ move event mask and menu
['] DiskDrvr drvrName + openMe \ try to open this driver
IF ( not OK ) unitNum DrvrRem
['] Scsidisk (call) DisposPtr
bra @1 \ exit hack.
\ This is the Mach2 equivalent of the
\ Ugly Goto Statement in Pascal.
\ Sorry, but it is so much easier this way...
THEN
hdce @ -> dce \ deref this handle again, may have changed
dce dCtlStorage + @ -> ourVars
ID ourVars ourID + w!
partition IF
\ well, we should have a non-NIL partition at least...
partition ( PDSig + ) w@ PDSigWord = IF
\ and it should be a Macintosh one. The NEW Apple drivers
\ have a different sig word and DPM format that you
\ might want to take into account here (see text).
partition 2+ -> pt
BEGIN
pt PDFSID + @ ?dup WHILE \ otherwise no good partition found
"tfs1 =
IF ( correct file system ID )
pt @ ourVars Offset + !
pt 4 + @ xchg ( long drive size, hi word <-> lo word )
ourVars realSize + !
SysEvtMask w@ 0= IF \ we're booting
dce dCtlFlags + dup w@ $2000 OR swap w!
( set dNeedTime flag )
1 dce dCtlDelay + w!
1 ourVars TickleFlag + c!
THEN
THEN
12 +> pt
REPEAT
THEN THEN
@1 UNLK A2 \ which was used for local variables
MOVEM.L (A7)+,A2-A6/D2-D7 ( restore registers )
UNLK A6
RTS \ we stop here; the rest will be inaccessible junk (4 bytes).
;
: DrOpen DA.prelude DiskOpen DA.epilogue ;
: DrClose DA.prelude DiskClose DA.epilogue ;
: DrCtl DA.prelude DiskControl DA.JIODone ;
: DrStatus DA.prelude DiskStatus DA.JIODone ;
: DrPrime DA.prelude DiskPrime DA.JIODone ;
' DrOpen ' DrPrime ' DrCtl ' DrStatus ' DrClose
$6F00 0 0 0 ( flags delay mask menu )
" .SCSIfth" ( name, MUST start with a period )
;DA
' RealInstall ;XDEF
\ —————————————————————————————————————————
\ The following routines are to be added or replaced in the
\ installer program from the previous column. Included is an
\ installer that will directly move the Forth code to disk, without
\ going through a resource, and some code to install the driver
\ in memory for testing without writing it to the disk. The
\ DDM and DPM definitions have been changed somewhat to accommodate
\ the larger driver, and to have the partition start at the same
\ place that Apple's new SCSI driver expects it (so that you can
\ replace the Forth driver easily by a new Apple driver in case
\ you are fed up with this hack)
\ Good luck. - JL -
\ —————————————————————————————————————————
hex
: create.ddm
ddm 200 0 fill
4552 ddm w!
read.cap ddm 2+ w! ( block size )
ddm 4 + ! ( # of blocks )
0 ddm 8 + w! ( device type )
0 ddm A + w! ( device ID )
10 ddm C + ! ( first data block )
1 ddm 10 + w! ( one driver to follow )
4 ddm 12 + ! ( driver start block )
A ddm 16 + w! ( driver is 10 blocks long )
1 ddm 18 + w! ( and runs on Macintosh =1 )
;
: create.dpm
dpm 200 0 fill
5453 dpm w!
10 dpm 2+ ! ( starting block of partition )
read.cap drop 10 - dpm 6 + ! ( # of blocks )
"tfs1 dpm A + ! ( TFS1 signature )
0 dpm E + !
;
decimal
: read.ddm
0 read.blk 2+ w! 0 read.blk 4 + c!
1 read.blk 5 + c!
120 read.blk myDisk @ ddm 512 doscsi.r
2drop
;
: read.dpm
0 read.blk 2+ w! 1 read.blk 4 + c!
1 read.blk 5 + c!
120 read.blk myDisk @ dpm 512 doscsi.r
2drop
;
: write.ddm
0 write.blk 2+ w! 0 write.blk 4 + c!
1 write.blk 5 + c!
120 write.blk myDisk @ ddm 512 doscsi.w
2drop
;
: write.dpm
0 write.blk 2+ w! 1 write.blk 4 + c!
1 write.blk 5 + c!
120 write.blk myDisk @ dpm 512 doscsi.w
2drop
;
: get.sdrv { | length -- length }
['] scsidisk dup
xlen dup -> length driver.block swap cmove
length
;
: write.sdrv { length | sectors }
0 write.blk 2+ w! 4 write.blk 4 + c!
length 512 / 1+ dup write.blk 5 + c! -> sectors
120 write.blk myDisk @ driver.block sectors 512 * doscsi.w
cr ." Driver written. Stat, Mess = " . .
;
: dmp { block# | -- } ( for easy testing of SCSI disk contents )
0 read.blk 2+ w! block# read.blk 4 + c!
1 read.blk 5 + c!
120 read.blk myDisk @ ddm 512 doscsi.r
2drop
ddm 20 dump
;
.TRAP _newptr,sys $A51E
$308 CONSTANT DQHeader
6 CONSTANT QTail
VARIABLE syshp.drvr
: install.driver { | dstart dlength dbytes pointer -- }
read.ddm
ddm 18 + @ -> dstart
ddm 22 + w@ -> dlength
cr ." Driver starts at sector " dstart .
." and is " dlength . ." sectors long."
dlength 512 * -> dbytes
dstart 256 /mod read.blk 2+ w! read.blk 4 + c!
dlength read.blk 5 + c!
120 read.blk myDisk @ driver.block dbytes doscsi.r
cr ." Driver read; stat, mess = " . .
dbytes MOVE.L (A6)+,D0
_newptr,sys ( get memory block in system heap )
MOVE.L A0,-(A6) -> pointer
pointer
IF driver.block pointer dbytes cmove
pointer syshp.drvr !
ELSE ." Not enough system heap for installation." cr
THEN
;
CODE call.driver
MOVE.L D5,-(A7)
MOVE.L (A6)+,D5
MOVE.L (A6)+,A0
execute
MOVE.L (A7)+,D5
RTS
END-CODE
: mount.scsi
install.driver
read.dpm
SysEvtMask @
0 SysEvtMask !
syshp.drvr @ dpm myDisk @ call.driver
SysEvtMask !
;
: zero.scsi
DQHeader qTail + @ dQDrive + w@ ( drive # found )
cr ." Do you want to zero the directory of drive # " dup . ." ? "
yesno if " JL's Hard Disk" call DIZero
cr ." Result code = " . cr
then
;
: mount
cr ." Looking for SCSI devices..."
get.disk
cr ." SCSI drive found at address " myDisk @ .
cr show.cap
cr ." format disk? "
yesno IF cr ." Do you REALLY want to erase this SCSI disk? "
yesno IF cr ." Reformatting disk... "
format
THEN
THEN
modenoattn
create.ddm create.dpm
write.ddm write.dpm
cr ." Device and partition descriptor maps written. "
get.sdrv
cr ." Writing driver ... "
write.sdrv
mount.scsi
zero.scsi
;
: install.mem { | dbytes pointer -- }
get.sdrv
['] scsidisk xlen dup -> dbytes
MOVE.L (A6)+,D0
_newptr,sys ( get memory block in system heap )
MOVE.L A0,-(A6) -> pointer
pointer
IF driver.block pointer dbytes cmove
pointer syshp.drvr !
ELSE ." Not enough system heap for installation." cr
THEN
;
: mount.mem
install.mem
read.dpm
SysEvtMask @
0 SysEvtMask !
syshp.drvr @ dpm myDisk @ call.driver
SysEvtMask !
;